Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPM 1.2 support #12204

Merged
merged 42 commits into from
Sep 30, 2024
Merged

GPM 1.2 support #12204

merged 42 commits into from
Sep 30, 2024

Conversation

javagl
Copy link
Contributor

@javagl javagl commented Sep 18, 2024

Summary

The document "The Generic Point-cloud Model (GPM): Implementation and Exploitation, Version 1.2, 2024-02-29" from the National Geospatial-Intelligence Agency (NGA) is published at https://nsgreg.nga.mil/csmwg.jsp .

And I'll now try to summarize a 264 page document in one paragraph 😎 :

The "GPM" is the "Generic Point-cloud Model", and describes methods for modeling error propagation (or "uncertainty") within point clouds that have been acquired e.g. with LIDAR scanners, for the use in a geospatial context. In GPM Version 1.2, these concepts have been generalized to be applicable to meshes. The idea is to store error metadata inside a glTF, using a glTF extension. The main elements of the data can very roughly be summarized to be "anchor points", which are a sort of reference points with a known location and known error/uncertainty, and "per-point errors" (PPE), which, in the case of mesh data, are stored in a texture. The anchor points are stored at the top-level of the glTF. The per-point error textures are associated with mesh primitives, similar to Property Textures in EXT_structural_metadata.

Description

The current (DRAFT) state of this PR:

  • There are classes that reflect the structure of the GPM data more or less direcly.
    • These are currently located in a Source/Scene/Model/Extensions/Gpm subfolder.
    • They mimic the structures of the JSON schema that defines the extension, with minor adjustments for the CesiumJS API (e.g. using a Cartesian3 instead of a number[3] array for some position and such). We can argue about the 1:1 mapping of the JSON schema structures. The result may be "inconvenient" in some way. But trying to find a good "convenience layer" requires a deep understanding of the goals and usage patterns.
    • Related: We can talk about the naming. There's a class like Spdcf. It could be called StrictlyPositiveDefiniteCorrelationFunction. If someone thinks that it should be renamed: Please suggest sensible names for its properties A and T here as well...
  • These classes are filled with life during loading, starting from the GltfLoader
    • There are two new loaders, GltfGpmLoader and GltfMeshPrimitiveGpmLoader, that are hooked into the GltfLoader
    • The GltfGpmLoader loads the top-level GPM information, and offers it as the classes described above
    • The GltfMeshPrimitiveGpmLoader loads the GPM information for each mesh primitive. This involves loading the PPE (per-point error) textures. Right now, this data is translated into instances for "structural metadata", like EXT_structural_metdata, but there are many details to be sorted out here...

Some high-level considerations:

The extension is probably not something that could be considered as "the most widely used core functionality of CesiumJS". And I think that it could make sense to have an infrastructure (or at least some ideas) about how to handle ~"highly use-case specific (vendor) glTF extensions" in general. This could go as far as establishing some "plugin-concept" that allows plugging in loaders for specific extensions into the GltfLoader, and transporting the parsed and loaded data back to the client.

Right now, for the GPM data, this is done ... very pragmatically. The Model/Extensions/Gpm subdirectory already suggests that there might be other directories in Model/Extensions/... that contain the respective extension classes. The loaders are currently hard-wired into the GltfLoader, but it might be relatively easy to find some sort of abstraction there. The question about how to transport the extension information to the client is still open.
The apprach here right now is:

  • There is a new ModelComponents.extensions dictionary that can store "anything"
  • The GltfGpmLoader loads the GPM JSON, translates it into an object, and this is eventually just stored as
    loader._components.extensions["NGA_gpm_local"] = gpmLoader._gltfGpmLocal;
  • There is a function Model3DTileContent.getExtension that just forwards to Model.getExtension, and allows clients to obtain that parsed data like
    const extensionObject = modelContent.getExtension("NGA_gpm_local")
    (the point is: There should probably not be some Model.getNgaGpmLocal function in the Model class...)

Details about the point that the 'mesh primitive GPM data' is currently translated into something that resembles EXT_structural_metadata will be added here soon. But there are too many details to be sorted out (and that are likely to change) to explain that right now.

Testing plan

Beyond the unit tests, I have added a sandcastle for testing this in #12204 (comment)

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

Copy link

Thank you for the pull request, @javagl!

✅ We can confirm we have a CLA on file for you.

@javagl
Copy link
Contributor Author

javagl commented Sep 25, 2024

The last commits consisted of

  • Cleanups (like letting the GltfGpmLoader not unnecessarily implement ResourceLoader)
  • Making the conversion from the "original" GPM data into structural metadata more explicit
  • Adding tests

What is still missing: Mentioning this in CHANGES.md. We should emphasize that this is a "preview feature", offered for early feedback, and some details may still change in future releases.


On the side of the user, the access to the data that is parsed from the root-level GPM extension should now be simple. Given Model3DTileContent (as obtained from a tile), the parsed extension object can be obtained as

const extensionObject = modelContent.getExtension("NGA_gpm_local");

The returned object will be a GltfGpmLocal, which mimics the structures from the JSON schema definition (with minor conversions to the CesiumJS API - e.g. creating a Cartesian3 instead of a number[3] for a point position).

For the GPM data that is stored in the mesh primitives (similar to property textures), there currently is no way of obtaining that data explicitly in its original form: In order to be usable in CesiumJS (e.g. for custom shaders), the data is internally converted into a StructuralMetadata object.

Some details of this conversion are (intentionally) not really "specified". There are some caveats with that. For example, when a glTF contains both the NGA_gpm_local extension and EXT_structural_metadata, then the latter will essentially be overwritten. We still have to decide how the NGA_gpm_local extension data can be made accessible in a form that allows it to be used as an input for custom shaders, without overwriting the structural metadata, and conversely, without having to make the whole CesiumJS metadata infrastructure aware of the NGA_gpm_local extension...


The following is a Sandcastle that is extracted from an existing demo, and focusses on the aspects of the GPM support that are implemented here:

  • It allows selecting one of two data sets from Cesium ion that contain GPM data
  • It shows the (indirect!) 'anchor points' from the root level of the glTFs
    • (We only have data sets with indirect anchor points for now...)
  • It allows visualizing the PPE textures from the mesh primitive level of the glTFs
    • This is done with custom shaders, building upon the translation of GPM data into structural metadata

Cesium GPM Sandcastle 0002

(The sandcastle refers to localhost until this PR is merged)

http://localhost:8080/Apps/Sandcastle/#c=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

@javagl javagl marked this pull request as ready for review September 25, 2024 14:22
Copy link
Contributor

@ggetz ggetz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @javagl! We talked with @lilleyse offline– He mentioned that he took a look at the overall approach here and that it looks good 👍

My comments are much more about the API and how we can communicate the (experimental) change to users.


Please merge in main when you can. Please see @jjspace's instructions to streamline merging the recent prettier updates.


The following is a Sandcastle that is extracted from an existing demo...

Can we commit this to the repo for reference? I think it can live under the "Development" Sandcastle examples so that it does not get published to the cesium.com deployment of Sandcastle.


What is still missing: Mentioning this in CHANGES.md. We should emphasize that this is a "preview feature", offered for early feedback, and some details may still change in future releases.

I see that most of the new code here is not exposed in the public API. So, if I was adding to CHANGES.md, mention the added support in Model, and then add the caveat "This feature is not final and is subject to change without Cesium's standard deprecation policy."

Additionally, we have a comment in Model.js that says "Cesium supports glTF assets with the following extensions:" Can we add this extension to the list, with the same caveat?


We can talk about the naming. There's a class like Spdcf. It could be called StrictlyPositiveDefiniteCorrelationFunction. If someone thinks that it should be renamed: Please suggest sensible names for its properties A and T here as well...

I know it's verbose, but I don't think "SPDCF" is common enough that the abbreviation should be used, as per the coding guide. I'm open to a compromise as of one or two descriptive words in there.

This is definitely from the perspective of someone who is trying to understand via the code first instead of being familiar with the extension– However I expect this will be most people's experience while debugging. At the very minimum, can we link to spec where a developer can find more info?


And I think that it could make sense to have an infrastructure (or at least some ideas) about how to handle ~"highly use-case specific (vendor) glTF extensions" in general. This could go as far as establishing some "plugin-concept" that allows plugging in loaders for specific extensions into the GltfLoader, and transporting the parsed and loaded data back to the client.

I think this a good idea. Given the timeline on this PR and the desire to constrain the scope, I would say we should move forwards with the approach in this PR for now. But I think "loader plugin" concept would be great for extensibility in the future. Does it make sense to open an issue and discuss further?

Comment on lines 1787 to 1788
* @private
* @experimental This feature is subject to change without Cesium's standard deprecation policy.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While there is an argument to be made for this being a private function, I'm curious as to why this is marked as experimental. It does not seem to be coupled to the GPM extension at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, model.getExtension(...) can only refer to an extension object from the root of the glTF. The GPM extension also contains extension objects in the mesh primitives. And it is by no means clear how ~"elements of a glTF" should/could be made accessible (even less their extensions).

But I can remove that part of the comment. @private might be enough.

* this will return the model representation of the extension.
*
* @param {string} extensionName The name of the extension
* @returns The object, or `undefined`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @returns The object, or `undefined`
* @returns {object|undefined} The object, or `undefined`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the object here should always be an instance of a ResourceLoader, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The object that is returned there is of the type that the object has after parsing it from the extension JSON. In this case, it will have the type GltfGpmLocal.

packages/engine/Source/Scene/GltfLoader.js Show resolved Hide resolved
* @private
* @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
*/
function PpeTexture(options) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the options object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


/**
* Create the JSON description of a metadata class that treats
* the given PPE texture as a property texture property(!).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* the given PPE texture as a property texture property(!).
* the given PPE texture as a property texture property.

Love the enthusiasm though 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

},
});

GltfMeshPrimitiveGpmLoader.prototype.loadResources = async function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, I might suggest marking functions used internally only with an underscore, ie. GltfMeshPrimitiveGpmLoader.prototype._loadResources.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now added some underscores there. On a certain level, this should not be necessary, because the whole class is tagged as @private, meaning that everything within this class already is private. And given that things like

ResourceLoader.prototype.unload = function () {};
are marked as private and do not have an undescore, I assume that "internally" basically means "in this file" here.

(This can make sense, as a concept, but ... consistency is difficult. And I know that many of these difficulties can be attributed to the underlying "programming "language""...)

@javagl
Copy link
Contributor Author

javagl commented Sep 27, 2024

I addressed some (most) of the inlined comments.

There are a few open ones, related to private/experimental - details below


Can we commit this to the repo for reference? I think it can live under the "Development" Sandcastle examples so that it does not get published to the cesium.com deployment of Sandcastle.

The task to create demos is already on my TODO list. Depending on the intended structure, this could be separate demos for this PR and the "Metadata Picking", or it could be one that replaces https://demos.cesium.com/owt-gpm/ , which combines both features.

(Is it criticial that this sandcastle becomes part of this PR?)


So, if I was adding to CHANGES.md, mention the added support in Model, and then add the caveat "This feature is not final and is subject to change without Cesium's standard deprecation policy."
...
Additionally, we have a comment in Model.js that says "Cesium supports glTF assets with the following extensions:" Can we add this extension to the list, with the same caveat?

I added the comment Model.js and CHANGES.md, calling it experimental - I did not repeat the disclaimer about the deprecation policy, but can add that explicitly, if desired (also see notes below):


Regarding private/experimental:

I see that most of the new code here is not exposed in the public API.

Right now, most of the classes are tagged with both. This does not make much sense. But considering that clients should be able to obtain these structures, via that getExtension call, they are rather not private, but definitely experimental.

Unless you disagree, I'd remove the private where appropriate (but will keep the experimental tag, of course).

(I'll do this together with the remaining JSDoc fixes)


About the renaming: As mentioned in the first post: I can rename Spdcf to StrictlyPositiveDefiniteCorrelationFunction (or maybe just "CorrelcationFunction" or so). But it has properties A and T. Should they be renamed as well? Should PpeTexture be renamed to PerPointErrorTexture? There's a pending PR for the 3D Tiles GPM extension. It will contain structures that are called EcefCoord, EpsgEcef, and EpsgUtm... There certainly is some tension between "consistency with existing naming schemes" and "consistency with the specification"...

@ggetz
Copy link
Contributor

ggetz commented Sep 27, 2024

(Is it criticial that this sandcastle becomes part of this PR?)

Nope. But I do think having one or both committed to the repo eventually (rather than deployed separately to demos.cesium.com) will be useful. I'm thinking that we want to have it in place to ensure that other changes do not break this feature, beyond just unit tests.

Right now, most of the classes are tagged with both. This does not make much sense. But considering that clients should be able to obtain these structures, via that getExtension call, they are rather not private, but definitely experimental.

Overall, I was actually thinking the other way around: It does make sense that most of the new code is private API, since users of CesiumJS will only ever use it by loading a model that has the new extension. Therefore, no need to note the experimental tag on private APIs, and no need to mention private APIs in CHANGES.md.

But yes, anywhere a client can access a class via the API, it should not be marked as private (but still be marked as experimental). And any new public API should be mentioned in a bullet in CHANGES.md.

But it has properties A and T. Should they be renamed as well? Should PpeTexture be renamed to PerPointErrorTexture? There's a pending PR for the 3D Tiles GPM extension. It will contain structures that are called EcefCoord, EpsgEcef, and EpsgUtm... There certainly is some tension between "consistency with existing naming schemes" and "consistency with the specification"

I see why consistency between the spec and the implementation may be preferred. Perhaps if we provide a link to the spec for context in the inline documentation that would be sufficient.

@javagl
Copy link
Contributor Author

javagl commented Sep 27, 2024

Just a short note about the private/experimental part:

It does make sense that most of the new code is private API, since users of CesiumJS will only ever use it by loading a model that has the new extension.

I'll try to classify that sensibly in the next update pass (tomorrow). But the structures/classes in the Extensions/Gpm package are "public", insofar that the sandcastle code like

    const extensionObject = modelContent.getExtension("NGA_gpm_local");
    const anchorPoints =  extensionObject.anchorPointsIndirect;
...

will return an GltfGpmLocal object, and the client will access the AnchorPointIndirect array there.

@javagl
Copy link
Contributor Author

javagl commented Sep 28, 2024

The previous commits addressed most of the remaining inlined comments.

Two broader questions (and how I addressed them):


The private/experimental part:

Some classes are indeed private and not visible to clients at all - mainly, the GltfGpmLoader and GltfMeshPrimitiveGpmLoader. These are tagged as @private (without @experimental).

However, many of the classes that are created by these loaders are accessible for clients. Therefore, they are not tagged as @private - but of course, they are tagged as @experimental. (They will change, and pretty soon...)

There is a gray area between both:

Some structures, like the MeshPrimitiveGpmLocal and the PpeTexture classes are currently not accessible for clients. They are basically translated into StructuralMetadata internally, and only accessible indirectly then (via custom shaders, for example).

It might very well be that clients do want access to these objects at some point. Maybe they don't even want that translation to StructuralMetadata. Maybe they want to do something like
const ppeTexture = model.gltf.meshes[m].primitives[p].extensions["NGA_gpm_local"].ppeTextures[i];
instead, and use that PpeTexture object in some application-specific way.

Right now, these classes are tagged as @private. When they are offered in some form, then the @private will be replaced with @experimental. But how they are offered still has to be sorted out.


The names....

"There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors"

I know that names like Spdcf do not match the naming patterns in CesiumJS and the coding guide. But I think that one can make a good case for not even trying to come up with a "better" name here:

  • The classes have obscurely-named properties that basically cannot have sensible names
    • Something like spdcf.T is not much worse than strictlyPositiveDefiniteCorrelationFunction.T...
  • There is an upcoming PR that will include casses like EcefCoord, EpsgEcef, and EpsgUtm
    • No, there will be no class called EuropeanPetroleumSurveyGroupEarthCenteredEarthFixed...
  • Maybe the most important points
    • These names are taken from the specification, It is what it is.
    • The names match the definitions from the JSON schema. It's not our responsibility to come up with good names.
    • I'd really like to put some time into the wetzel generate-3dtiles-structure branch (or any other tool), to allow generating the whole code directly from the JSON schema. Basically 99% of the work that went into this PR could be completely automated (with the usual xkcd caveat, but ... it's not like this has never been done before...)

@@ -44,23 +44,23 @@
});

const fragmentShaderSource = `
uniform sampler2D colorTexture;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We updated some options in the prettier merge instructions to prevent unwanted trailing spaces like this from showing up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not immediately clear how this could be fixed "after the fact". I'd think that running npm run prettier on the current state and committing all the changed should fix "everything" (and that the current CI shouldn't even pass when there was still something wrong). But I can have a closer look (and maybe try to better understand what's actually done in the merge instructions - for now, I just followed them "blindly"...)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. To clean up this particular PR for now, I would recommend checking out the previous unchanged files (Apps/Sandcastle/*, packages/engine/Source/Scene/ArcGisMapServerImageryProvider.js, etc) from main and committing to this branch.

CC @jjspace

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it didn't work when pulling them from 'main', but with
git checkout post-prettier-v3 -- "Apps/Sandcastle/gallery/Custom Post Process.html"
(for all relevant files), it seemed to work - at least, the files do no longer show up as 'modified' here.

@ggetz
Copy link
Contributor

ggetz commented Sep 30, 2024

Thanks @javagl! I think this should be good to go.

Please see my comment about documenting a potential follow-up: https://github.com/CesiumGS/cesium/pull/12204/files#r1781500043

@ggetz ggetz merged commit e3e9837 into main Sep 30, 2024
9 checks passed
@ggetz ggetz deleted the gpm-support branch September 30, 2024 17:28
@javagl
Copy link
Contributor Author

javagl commented Sep 30, 2024

I added the comment that you linked to, and the other open points (from the metadata picking PR) in a follow-up issue at #12225 - I'll scan the reviews again to see whether I overlooked something, and extend that issue as necessary.

@javagl javagl mentioned this pull request Oct 5, 2024
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants